回溯法 之 八皇后问题

原文链接:http://blog.csdn.net/crayondeng/article/details/17174557

回溯法

回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一种即带有系统性又带有跳跃性的搜索算法。它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一结点时,先判断该节点是否包含问题的解。如果不包含,则跳过对以该节点为根的子树的搜索,逐层向其它祖先节点回溯。否则,进入该子树,继续按照深度优先策略搜索。回溯法求问题的所有解时,要回溯到根,且根节点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。这种以深度优先方式系统搜索问题的算法称为回溯法,它是用于解组合数大的问题。

回溯法的基本思想

确定了解空间的组织结构后,回溯法从根节点出发,以深度优先搜索方式搜索整个解空间。回溯法以这种工作方式递归地在解空间中搜索,直到找到所要求的解或解空间所有解都被遍历过为止。
回溯法搜索解空间树时,通常采用两种策略避免无效搜索,提高回溯法的搜索效率。其一是用约束函数在当前节点(扩展节点)处剪去不满足约束的子树;其二是用限界函数剪去得不到最优解的子树。这两类函数统称为剪枝函数。

回溯法解题通常包含以下三个步骤:

1.针对所给问题,定义问题的解空间;
2.确定易于搜索的解空间结构;
3.以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。


回溯法的实现

有两种方法:递归回溯和迭代回溯(非递归实现)
下面给出这两个回溯实现的一般方法。

递归回溯:



迭代回溯:




在回溯法中有一个经典的问题八皇后问题

---- 以下有关八皇后问题介绍来着wikipedia。

八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n当且仅当 n = 1 或 n ≥ 4 时问题有解

历史

八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。

艾兹格·迪杰斯特拉在1972年用这个问题为例来说明他所谓结构性编程的能力[2]

八皇后问题在1990年代初期的著名电子游戏第七访客NDS平台的著名电子游戏雷顿教授与不可思议的小镇中都有出现。

八皇后问题的解

八皇后问题一共有 92 个互不相同的解。如果将旋转和对称的解归为一种的话,则一共有12个独立解,具体如下:

Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解1
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解2
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解3
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解4
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解5
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解6
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解7
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解8
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解9
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解10
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解11
Chess zhor 26.svg
Chess zver 26.svg
a8b8c8d8e8f8g8h8
a7b7c7d7e7f7g7h7
a6b6c6d6e6f6g6h6
a5b5c5d5e5f5g5h5
a4b4c4d4e4f4g4h4
a3b3c3d3e3f3g3h3
a2b2c2d2e2f2g2h2
a1b1c1d1e1f1g1h1
Chess zver 26.svg
Chess zhor 26.svg
独立解12

解的个数

下表给出了 n 皇后问题的解的个数包括独立解U(OEIS中的数列A002562)以及互不相同的解D(OEIS中的数列A000170)的个数:

n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 .. 24 25 26
U:10012161246923411,7879,23345,752..28,439,272,956,934275,986,683,743,4342,789,712,466,510,289
D:100210440923527242,68014,20073,712365,596..227,514,171,973,7362,207,893,435,808,35222,317,699,616,364,044

可以注意到六皇后问题的解的个数比五皇后问题的解的个数要少。现在还没有已知公式可以对 n 计算 n 皇后问题的解的个数。



下面正式进入编程阶段咯:

在下面的代码中给出了递归方法实现和迭代方法实现的八皇后问题!

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cmath>  
  3. #include <cstring>  
  4. using namespace std;  
  5.   
  6. int queen[9];  
  7.   
  8. //数组初始化  
  9. void init()  
  10. {  
  11.     memset(queen,0,9*sizeof(int));  
  12. }  
  13.   
  14. //输出结果  
  15. void print()  
  16. {  
  17.     for(int i=1; i<9; i++) cout<<queen[i]<<"  ";  
  18.     cout<<endl;  
  19. }  
  20.   
  21. //剪枝函数  
  22. bool canPlaceQueen(int k)  
  23. {  
  24.     for(int i = 1; i < k; i++)  
  25.     {  
  26.         //判断是否处于同一列或同一斜线  
  27.         if(queen[i] == queen[k] || abs(k-i) == abs(queen[k]-queen[i])) return false;  
  28.     }  
  29.     return true;  
  30. }  
  31. //迭代方法求解八皇后过程  
  32. void eightQueen_1()  
  33. {  
  34.     int k = 1;  
  35.     while(k>=1)  
  36.     {  
  37.         while(queen[k]<=7)  
  38.         {  
  39.             queen[k] += 1;  
  40.             if(k == 8 && canPlaceQueen(k))  
  41.             {  
  42.                 print();  
  43.             }  
  44.             else if(canPlaceQueen(k))  
  45.             {  
  46.                 k++;  
  47.             }  
  48.         }  
  49.         queen[k] = 0;  
  50.         k--;  
  51.     }  
  52. }  
  53.   
  54. //递归方法求解八皇后过程  
  55. void eightQueen_2(int k)  
  56. {  
  57.     for(int i=1; i<9; i++)  
  58.     {  
  59.         queen[k] = i;  
  60.         if(k == 8 && canPlaceQueen(k))  
  61.         {  
  62.             print();  
  63.             return;  
  64.         }  
  65.         else if(canPlaceQueen(k))  
  66.         {  
  67.             eightQueen_2(k+1);  
  68.         }  
  69.     }  
  70. }  
  71. int main()  
  72. {  
  73.     init();  
  74.     eightQueen_1();  
  75. //    eightQueen_2(1);  
  76.     return 0;  
  77. }  

过程比较简单,就不多细说了,关于n皇后问题,通过对上面代码的稍加改动也可以实现。

运行输出结果:
[cpp]  view plain  copy
  1. 1  5  8  6  3  7  2  4  
  2. 1  6  8  3  7  4  2  5  
  3. 1  7  4  6  8  2  5  3  
  4. 1  7  5  8  2  4  6  3  
  5. 2  4  6  8  3  1  7  5  
  6. 2  5  7  1  3  8  6  4  
  7. 2  5  7  4  1  8  6  3  
  8. 2  6  1  7  4  8  3  5  
  9. 2  6  8  3  1  4  7  5  
  10. 2  7  3  6  8  5  1  4  
  11. 2  7  5  8  1  4  6  3  
  12. 2  8  6  1  3  5  7  4  
  13. 3  1  7  5  8  2  4  6  
  14. 3  5  2  8  1  7  4  6  
  15. 3  5  2  8  6  4  7  1  
  16. 3  5  7  1  4  2  8  6  
  17. 3  5  8  4  1  7  2  6  
  18. 3  6  2  5  8  1  7  4  
  19. 3  6  2  7  1  4  8  5  
  20. 3  6  2  7  5  1  8  4  
  21. 3  6  4  1  8  5  7  2  
  22. 3  6  4  2  8  5  7  1  
  23. 3  6  8  1  4  7  5  2  
  24. 3  6  8  1  5  7  2  4  
  25. 3  6  8  2  4  1  7  5  
  26. 3  7  2  8  5  1  4  6  
  27. 3  7  2  8  6  4  1  5  
  28. 3  8  4  7  1  6  2  5  
  29. 4  1  5  8  2  7  3  6  
  30. 4  1  5  8  6  3  7  2  
  31. 4  2  5  8  6  1  3  7  
  32. 4  2  7  3  6  8  1  5  
  33. 4  2  7  3  6  8  5  1  
  34. 4  2  7  5  1  8  6  3  
  35. 4  2  8  5  7  1  3  6  
  36. 4  2  8  6  1  3  5  7  
  37. 4  6  1  5  2  8  3  7  
  38. 4  6  8  2  7  1  3  5  
  39. 4  6  8  3  1  7  5  2  
  40. 4  7  1  8  5  2  6  3  
  41. 4  7  3  8  2  5  1  6  
  42. 4  7  5  2  6  1  3  8  
  43. 4  7  5  3  1  6  8  2  
  44. 4  8  1  3  6  2  7  5  
  45. 4  8  1  5  7  2  6  3  
  46. 4  8  5  3  1  7  2  6  
  47. 5  1  4  6  8  2  7  3  
  48. 5  1  8  4  2  7  3  6  
  49. 5  1  8  6  3  7  2  4  
  50. 5  2  4  6  8  3  1  7  
  51. 5  2  4  7  3  8  6  1  
  52. 5  2  6  1  7  4  8  3  
  53. 5  2  8  1  4  7  3  6  
  54. 5  3  1  6  8  2  4  7  
  55. 5  3  1  7  2  8  6  4  
  56. 5  3  8  4  7  1  6  2  
  57. 5  7  1  3  8  6  4  2  
  58. 5  7  1  4  2  8  6  3  
  59. 5  7  2  4  8  1  3  6  
  60. 5  7  2  6  3  1  4  8  
  61. 5  7  2  6  3  1  8  4  
  62. 5  7  4  1  3  8  6  2  
  63. 5  8  4  1  3  6  2  7  
  64. 5  8  4  1  7  2  6  3  
  65. 6  1  5  2  8  3  7  4  
  66. 6  2  7  1  3  5  8  4  
  67. 6  2  7  1  4  8  5  3  
  68. 6  3  1  7  5  8  2  4  
  69. 6  3  1  8  4  2  7  5  
  70. 6  3  1  8  5  2  4  7  
  71. 6  3  5  7  1  4  2  8  
  72. 6  3  5  8  1  4  2  7  
  73. 6  3  7  2  4  8  1  5  
  74. 6  3  7  2  8  5  1  4  
  75. 6  3  7  4  1  8  2  5  
  76. 6  4  1  5  8  2  7  3  
  77. 6  4  2  8  5  7  1  3  
  78. 6  4  7  1  3  5  2  8  
  79. 6  4  7  1  8  2  5  3  
  80. 6  8  2  4  1  7  5  3  
  81. 7  1  3  8  6  4  2  5  
  82. 7  2  4  1  8  5  3  6  
  83. 7  2  6  3  1  4  8  5  
  84. 7  3  1  6  8  5  2  4  
  85. 7  3  8  2  5  1  6  4  
  86. 7  4  2  5  8  1  3  6  
  87. 7  4  2  8  6  1  3  5  
  88. 7  5  3  1  6  8  2  4  
  89. 8  2  4  1  7  5  3  6  
  90. 8  2  5  3  1  7  4  6  
  91. 8  3  1  6  2  5  7  4  
  92. 8  4  1  3  6  2  7  5  

上面一共输出的是92个结果。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值